package cn.jjxx.modules.sso.service.impl;

import java.io.IOException;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.jjxx.core.model.AjaxJson;
import cn.jjxx.core.utils.ObjectUtils;
import cn.jjxx.core.utils.ServletUtils;
import cn.jjxx.modules.sso.entity.TokenEntity;
import cn.jjxx.modules.sso.service.ISSOServerService;
import cn.jjxx.modules.sso.utils.TokenUtil;
import cn.jjxx.modules.sso.utils.UrlUtil;
import cn.jjxx.modules.sys.entity.User;
import cn.jjxx.modules.sys.service.IUserService;
import cn.jjxx.modules.sys.service.impl.PasswordService;

@Service
public class SSOServerService implements ISSOServerService{
	
	@Autowired
	protected IUserService userService;
	@Autowired
	private PasswordService passwordService;

	
	@Override
	public void checkLogin(TokenEntity tokenEntity, HttpServletRequest request,HttpServletResponse response) throws IOException {
		String userId = (String)request.getSession().getAttribute("userId");
		//未登录跳转到客户端登录页面（也可以是服务器自身拥有登录界面）
		if(userId==null){
			String redirectUrl = tokenEntity.getClientUrl()+"?appName="+tokenEntity.getAppName();
			response.sendRedirect(redirectUrl);
		}else{
			//以登录携带令牌原路返回
			String token = UUID.randomUUID().toString();
			//存储
			TokenUtil.put(token, userId);
			String redirectUrl = tokenEntity.getClientUrl()+"?token="+token+"&allSessionId="+request.getSession().getId();
			response.sendRedirect(redirectUrl);
		}
	}

	@Override
	public AjaxJson tokenCheck(TokenEntity token) {
		AjaxJson ajaxJson = new AjaxJson();
		String userId = TokenUtil.get(token.getToken());
		//token一次性的，用完即毁
		TokenUtil.remove(token.getToken());
		if(userId!=null){
			//存储地址信息，用于退出时销毁
			String url=UrlUtil.get(token.getAllSessionId());
			if(url==null){
				url=token.getLogoutUrl();
			}else{
				url+=","+token.getLogoutUrl();
			}
			UrlUtil.put(token.getAllSessionId(), url);
			//返回认证结果
			ajaxJson.setMsg("认证成功!");
			ajaxJson.setData(userId);
		}else{
			ajaxJson.setRet(AjaxJson.RET_FAIL);
			ajaxJson.setMsg("认证失败!");
		}
		return ajaxJson;
	}

	@Override
	public void ssoLogin(User user, HttpServletRequest request, HttpServletResponse response) throws IOException {
		String username = user.getUsername();
		String password = user.getPassword();
		String redirectUrl=request.getParameter("redirectUrl");
		User u = userService.findByUsername(username);
		//通过用户名去查询数据库账号,对比账号和加密后密码是否一致
		if(!ObjectUtils.isNullOrEmpty(u)&&checkPassword(password, u)){
			//TODO 找到所有子系统，进行登录
			//TODO 当前系统登录成功时，子系统对应的账号
			//设置状态(通过session判断该浏览器与认证中心的全局会话是否已经建立)，生成令牌
			request.getSession().setAttribute("userId", u.getId());
			String token = UUID.randomUUID().toString();
			//存储
			TokenUtil.put(token, u.getId());
			//将token发送给客户端,附带本次全局会话的sessionId
			String allSessionId=request.getSession().getId();
			String url = redirectUrl+"?token="+token+"&allSessionId="+allSessionId;
			response.sendRedirect(url);
		}
		//认证不成功时
		response.sendRedirect(redirectUrl);
	}

	@Override
	public boolean ssoLogout() {
		HttpServletRequest request = ServletUtils.getRequest();
		String allSessionId=request.getSession().getId();
		String url=UrlUtil.get(allSessionId);
		UrlUtil.remove(allSessionId);
		//删除全局会话
		request.getSession().removeAttribute("userId");
		//通知各个客户端删除局部会话
		String [] urls=url.split(",");
		//使用httpClient通知客户端的时候发现是新建立了一个服务器与客户端的会话，导致sessionId和客户建立的局部会话id不相同，无法做到删除局部会话
		HttpClient httpClient=new HttpClient();
		PostMethod postMethod=new PostMethod();
		for (String u : urls) {
			postMethod.setPath(u);
			postMethod.addParameter("allSessionId", allSessionId);
			try {
				httpClient.executeMethod(postMethod);
				postMethod.releaseConnection();
			} catch (HttpException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return true;
	}

	/**
	 * @Description: 检测传入的密码是否与原始密码一致 .<br>
	 * @param password 传入的密码.<br>
	 * @param u u.getPassword()为原始密码.<br>
	 * @return .<br>   
	 * @author zcg .<br>
	 * @date 2020-1-17 上午10:44:29.<br>
	 */
	boolean checkPassword(String password, User u){
		String newPassword = new SimpleHash(PasswordService.mName,password,
		ByteSource.Util.bytes(u.getCredentialsSalt()), PasswordService.anInt).toHex();
		if(newPassword.equals(u.getPassword())){
			return true;
		}
		return false;
	}
	
}
